#pragma once
#include <cstdlib>
#include <new>
#include <mutex>
#include <atomic>

namespace rsv
{
    template<typename T, bool LongLifeTime = false> class singleton;

    template<typename T>
    class singleton<T, false>
    {
    public:
        template<typename... Args>
        static T& instance(Args&&... args) {
            static T obj(std::forward<Args>(args)...);
            return obj;
        }

    protected:
        singleton() = default;
        virtual ~singleton() {}

    private:
        singleton(const singleton&) = delete;
        singleton& operator=(const singleton&) = delete;
        singleton(singleton&&) = delete;
        singleton& operator=(singleton&&) = delete;
    };

    template<typename T>
    class singleton<T, true>
    {
    public:
        template<typename... Args>
        static T& instance(Args&&... args)
        {
            if (b_init_.load(std::memory_order_acquire))
            {
                return *pInstance_;
            }

            std::lock_guard<std::mutex> lock(lock_);
            if (b_init_.load(std::memory_order_relaxed))
            {
                return *pInstance_;
            }

            destroyed_ ? on_dead_reference(std::forward<Args>(args)...)
                    : create(std::forward<Args>(args)...);
    
            return *pInstance_;
        }

    private:
        template<typename... Args>
        static void create(Args&&... args) 
        {
            static T obj(std::forward<Args>(args)...);
            pInstance_ = &obj;
            //std::cout << "create pInstance_：" << pInstance_ << std::endl;
            b_init_.store(true, std::memory_order_release);//
        }

        template<typename... Args>
        static void on_dead_reference(Args&&... args)
        {
            create(std::forward<Args>(args)...);
            new(pInstance_) T(std::forward<Args>(args)...);
            std::atexit(kill_singleton);
            destroyed_ = false;
            //std::cout << "on_dead_reference pInstance_：" << pInstance_ << std::endl;
        }
        
        static void kill_singleton()
        {
            pInstance_->~singleton();
        }

        singleton(const singleton&);
        singleton& operator=(const singleton&);
        singleton(singleton&&);
        singleton& operator=(singleton&&);

        static std::mutex lock_;
    protected:
        singleton() = default;
        virtual ~singleton()
        {
            pInstance_ = nullptr;
            destroyed_ = true;
            b_init_.store(false, std::memory_order_release);
        }

        static T* pInstance_;
        static bool destroyed_;
        static std::atomic<bool> b_init_;
    };

    template<typename T> T* singleton<T, true>::pInstance_ = nullptr;
    template<typename T> bool singleton<T, true>::destroyed_ = false;
    template<typename T> std::mutex singleton<T, true>::lock_;
    template<typename T> std::atomic<bool> singleton<T, true>::b_init_ = false;
} // namespace rsv


#if 0
#pragma once
#include <cstdlib>
#include <new>
#include <mutex>
#include <atomic>

namespace rsv
{
    template<typename T, bool LongLifeTime = false> class singleton;

    template<typename T>
    class singleton<T, false>
    {
    public:
        template<typename... Args>
        static T& instance(Args&&... args) {
            static T obj(std::forward<Args>(args)...);
            return obj;
        }

    protected:
        singleton() = default;
        virtual ~singleton() {}

    private:
        singleton(const singleton&) = delete;
        singleton& operator=(const singleton&) = delete;
        singleton(singleton&&) = delete;
        singleton& operator=(singleton&&) = delete;
    };

    template<typename T>
    class singleton<T, true>
    {
    public:
        template<typename... Args>
        static T& instance(Args&&... args)
        {
            if(!pInstance_)
            {
                // DCL
                std::lock_guard<std::mutex> lock(lock_);

                if(!pInstance_)
                {
                    destroyed_ ? on_dead_reference(std::forward<Args>(args)...)
                            : create(std::forward<Args>(args)...);
                }
            }

            return *pInstance_;
        }

    private:
        template<typename... Args>
        static void create(Args&&... args) 
        {
            static T obj(std::forward<Args>(args)...);
            pInstance_ = &obj;
        }

        template<typename... Args>
        static void on_dead_reference(Args&&... args)
        {
            create(std::forward<Args>(args)...);
            new(pInstance_) T(std::forward<Args>(args)...);
            std::atexit(kill_singleton);
            destroyed_ = false;

        }
        
        static void kill_singleton()
        {
            pInstance_->~singleton();
        }


        singleton(const singleton&);
        singleton& operator=(const singleton&);
        singleton(singleton&&);
        singleton& operator=(singleton&&);

        static std::mutex lock_;

    protected:
        singleton() = default;
        virtual ~singleton()
        {
            pInstance_ = nullptr;
            destroyed_ = true;
        }

        static T* pInstance_;
        static bool destroyed_;
    };

    template<typename T> T* singleton<T, true>::pInstance_ = nullptr;
    template<typename T> bool singleton<T, true>::destroyed_ = false;
    template<typename T> std::mutex singleton<T, true>::lock_;
} // namespace rsv
#endif


#if 0
#pragma once
#include <cstdlib>
#include <new>
#include <mutex>
#include <atomic>

namespace rsv
{
    template<typename T, bool LongLifeTime = false> class singleton;

    template<typename T>
    class singleton<T, false>
    {
    public:
        template<typename... Args>
        static T& instance(Args&&... args) {
            static T obj(std::forward<Args>(args)...);
            return obj;
        }

    protected:
        singleton() = default;
        virtual ~singleton() {}

    private:
        singleton(const singleton&) = delete;
        singleton& operator=(const singleton&) = delete;
        singleton(singleton&&) = delete;
        singleton& operator=(singleton&&) = delete;
    };

    template<typename T>
    class singleton<T, true>
    {
    public:
        template<typename... Args>
        static T& instance(Args&&... args)
        {
            std::call_once(init_instance_flag_, [] (Args&&... args) {
                static T obj(std::forward<Args>(args)...);
                pInstance_ = &obj;
            }, std::forward<Args>(args)...);
            return *pInstance_;
        }

    private:
        singleton& operator=(const singleton&);
        singleton(singleton&&);
        singleton& operator=(singleton&&);

        static std::once_flag init_instance_flag_;

    protected:
        singleton() = default;
        virtual ~singleton()
        {
            pInstance_ = nullptr;
        }

        static T* pInstance_;
    };

    template<typename T> T* singleton<T, true>::pInstance_ = nullptr;
    template<typename T> std::once_flag singleton<T, true>::init_instance_flag_;
} // namespace rsv
#endif